const vscode = require('vscode');

class DragAndDropController {
    dropMimeTypes = ['application/vnd.code.tree.snippetStorage']; // 自定义 MIME 类型,唯一标记,用于识别拖拽的数据

    constructor(treeDataProvider) {
        this.treeDataProvider = treeDataProvider;
    }

    get onDidChangeTreeData() {
        return this.treeDataProvider.onDidChangeTreeData;
    }

    handleDrag(source, treeDataTransfer, token) {
        treeDataTransfer.set(this.dropMimeTypes[0], new vscode.DataTransferItem(source));
    }

    handleDrop(target, treeDataTransfer, token) {
        if (!target) return;

        const transferItem = treeDataTransfer.get(this.dropMimeTypes[0]);
        if (!transferItem) return;

        const draggedNodeList = transferItem.value; // 拖拽的节点
        const draggedNodeIdsMap = draggedNodeList.reduce((acc, node) => {
            return {
                ...acc,
                [node.id]: true
            }
        }, {})
        let treeData = JSON.parse(JSON.stringify(this.treeDataProvider.getStorageData())); // 树形数据

        // 禁止父子节点一起拖动
        let parentCount = 0, childCount = 0
        draggedNodeList.forEach(node => {
            if (node.children) parentCount++
            else childCount++
        })
        if (parentCount !== 0 && childCount !== 0) {
            vscode.window.showErrorMessage('父子节点不能一起拖动');
            return
        }

        const targetIsChild = !target.children // 目标是否为子节点
        const draggedIsChild = childCount !== 0 // 拖动的是否为子节点

        // 1、拖动子到子 => 插入到目标子位置之后
        if (draggedIsChild && targetIsChild) {
            // 找到目标节点的父级
            const targetParent = treeData.find(e => e.children?.find(c => c.id === target.id))
            // 删除treeData内拖动的子节点
            treeData.forEach(node => {
                node.children = node.children?.filter(e => !draggedNodeIdsMap[e.id]) || []
            })
            // 找到目标节点的索引
            const targetIndex = targetParent.children.findIndex(e => e.id === target.id)
            // 插入到目标节点之后
            targetParent.children.splice(targetIndex + 1, 0, ...draggedNodeList)
        }
        // 2、拖动子到父 => 插入的目标父的开头
        if (draggedIsChild && !targetIsChild) {
            // 删除treeData内拖动的子节点
            treeData.forEach(node => {
                node.children = node.children?.filter(e => !draggedNodeIdsMap[e.id]) || []
            })
            // 找到目标节点
            const targetNode = treeData.find(e => e.id === target.id)
            // 把拖动的子节点添加到目标父的开头
            targetNode.children = [...draggedNodeList, ...targetNode.children]
        }
        // 3、拖动父到子 => 插入到目标子的父级位置之后
        if (!draggedIsChild && targetIsChild) {
            vscode.window.showErrorMessage('父节点不能拖动到子节点');
            return
        }
        // 4、拖动父到父 => 插入到目标父位置之后
        if (!draggedIsChild && !targetIsChild) {
            // 拖动元素不能包含目标元素
            if (draggedNodeIdsMap[target.id]) return
            // 删除treeData内拖动的父节点
            treeData = treeData.filter(e => !draggedNodeIdsMap[e.id])
            // 找到目标节点的索引
            const targetIndex = treeData.findIndex(e => e.id === target.id)
            // 插入到目标节点之后
            treeData.splice(targetIndex + 1, 0, ...draggedNodeList)
        }

        this.treeDataProvider.updateData(treeData);
    }
}

module.exports = {
    DragAndDropController
}